The C and C++ language standards are among those that support the "volatile" type-qualifier for compiler operation. For example, as stated in the 1990 American National Standard for Information Systems--Programming Language C (hereinafter referred to as the "ANSI Standard"): "An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects."
A programmer may use the volatile type-qualifier for a variety of reasons, such as to enable accesses to shared memory, or to memory-mapped I/O locations (so as, for example, to communicate with external devices). Alternatively, the volatile type-qualifier may be used to enable access to locations that may be asynchronously accessed by an interrupt handler.
Accordingly, compilers, and more specifically compiler optimization phases, tend to be very conservative in the treatment of accesses to objects with volatile-qualified type in order to adhere to the standard and to accommodate the spectrum of applications of the volatile keyword. This conservative approach often results in a loss of compiler optimization opportunities and hence adversely affects run-time performance.
Compilers generally treat an access to a volatile type-qualified object in a universally inflexible manner. Specifically, for example,
a volatile load or store is never deleted or transformed into a register reference; PA1 a volatile load or store is emitted with an "ordered" completer to ensure sequential run-time hardware execution on weakly ordered systems; PA1 no memory reference instructions are scheduled across a volatile load or store; and PA1 a volatile load or store is never moved to a location where it could be executed "speculatively." PA1 a. relaxing asynchronicity of the access: a volatile access that is guaranteed to be synchronous allows local register promotion and eliminates redundant definition of volatile loads and stores. PA1 b. relaxing strong ordering requirements: if the underlying hardware does not need to observe strong ordering constraints when executing a volatile memory access, the corresponding load or store need not be marked with the ordered completer, which in turn allows faster execution of such references at run-time. PA1 c. relaxing constraints on compiler scheduling freedom: a volatile access that does not need to be executed sequentially relative to other non-volatile references can be scheduled better by the compiler. PA1 d. relaxing constraints on control speculation freedom: a volatile access that does not refer to a memory-mapped I/O location can be re-ordered to execute speculatively ahead of controlling branches, again leading to potentially higher run-time performance.
It is not always necessary to take such a universally inflexible approach. Sometimes selected optimizations could be allowed without endangering compilation integrity. These selected optimizations could help recover otherwise lost optimization opportunities and thereby enhance run-time performance.
Operating systems, in particular, have a need to declare a wide variety of data accesses as volatile in order to prevent incorrect compiler optimization of kernel code. However, this adversely affects performance, sometimes more than necessary. For instance, on weakly ordered systems, the volatile type-qualifier may be specified solely to ensure that the compiler emits a memory reference instruction to the volatile type-qualified object using a "strongly ordered" memory reference opcode or completer. In some programming applications, however, it may be perfectly acceptable for the compiler to perform certain selected optimizations, such as local register promotion on accesses using a "strongly ordered" completer, even though such transformations might not be safe to perform on all volatile references in general.
There is therefore a need for a regime of keywords that modify the general volatile type-qualifier, and whose selected use will permit (or not permit) certain optimization operations in compiling code containing references to volatile data.